﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="With_BitMask.cs" company="JDML Consulting Ltd.">
//   Copyright 2011 Photon Project - http://photon.codeplex.com
// </copyright>
// <summary>
//   Summary description for ModelBase
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace Photon.ComponentModel.Modelling
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
#if SILVERLIGHT
    using Microsoft.Silverlight.Testing;
#endif
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Testing;

    [TestClass, Tag("BitMask")]
    public class With_BitMask
    {
        private static readonly ReadOnlyCollection<bool> DefaultBitPattern = new ReadOnlyCollection<bool>(
            new[] { true, false, true, true, false, false, false, true, false, true, true, false, true, false, false, true, true, false });

        private static readonly ReadOnlyCollection<bool> UpdatedBitPattern = new ReadOnlyCollection<bool>(
            new [] { true, true, true, true, true, false, false, false, false, true, true, false, true, false, true, true, true, false });

        public TestContext TestContext { get; set; }
        
        private BitMask _systemUnderTest;

        private void AssertBitPattern(IList<bool> bitPattern)
        {
            Assert.AreEqual(bitPattern.Count, _systemUnderTest.Count);
            for (var i = 0; i < bitPattern.Count; i++)
            {
                Assert.AreEqual(bitPattern[i], _systemUnderTest[i], "Bit patterns differ at index {0}", i);
            }
        }

        private void AssertAllFalse()
        {
            for (var i = 0; i < _systemUnderTest.Count; i++)
            {
                Assert.IsFalse(_systemUnderTest[i], "Bit mask contained an unexpected value at index {0}", i);
            }
        }

        private static BitMask FromBitPattern(IList<bool> bitPattern)
        {
            var result = new BitMask(bitPattern.Count);
            ApplyBitPattern(result, bitPattern);
            return result;
        }
        
        private static void ApplyBitPattern(BitMask bitMask, IList<bool> bitPattern)
        {
            for (var i = 0; i < bitPattern.Count; i++)
            {
                bitMask[i] = bitPattern[i];
            }
        }

        [TestInitialize]
        public virtual void Given()
        {
        }

        [TestClass]
        public class When_creating_with_size_less_than_zero : With_BitMask
        {
            [TestMethod]
            public void Should_throw_argument_out_of_range_exception()
            {
                AssertException.Throws<ArgumentOutOfRangeException>(() => new BitMask(-1));    
            }
        }

        [TestClass]
        public class When_created_without_an_initial_size : With_BitMask
        {
            [TestInitialize]
            public override void Given()
            {
                _systemUnderTest = new BitMask();
            }

            [TestMethod]
            public void Should_initialize_count_to_zero()
            {
                Assert.AreEqual(0, _systemUnderTest.Count);
            }
        }

        [TestClass]
        public class When_created_with_an_initial_size : With_BitMask
        {
            [TestInitialize]
            public override void Given()
            {
                _systemUnderTest = new BitMask(33);
            }

            [TestMethod]
            public void Should_initialize_each_bit_position_to_false()
            {
                AssertAllFalse();    
            }

            [TestMethod]
            public void Should_initialize_count_to_size()
            {
                Assert.AreEqual(33, _systemUnderTest.Count);
            }
        }

        [TestClass]
        public class When_updated : With_BitMask
         {
            [TestInitialize] 
            public override void Given()
             {
                 _systemUnderTest = FromBitPattern(DefaultBitPattern);
             }

             [TestMethod]
             public void Should_be_able_to_read_updated_bits()
             {
                 AssertBitPattern(DefaultBitPattern);
             }
         }

        [TestClass]
        public class When_updating : With_BitMask
        {
            [TestInitialize]
            public override void Given()
            {
                _systemUnderTest = new BitMask(DefaultBitPattern.Count);
            }

            [TestMethod]
            public void Should_return_value_indicating_if_bit_was_changed()
            {
                for (var i = 0; i < DefaultBitPattern.Count; i++)
                {
                    Assert.AreEqual(DefaultBitPattern[i], _systemUnderTest.Update(i, DefaultBitPattern[i]));
                }
                
                for (var i = 0; i < UpdatedBitPattern.Count; i++)
                {
                    Assert.AreEqual(DefaultBitPattern[i] != UpdatedBitPattern[i], _systemUnderTest.Update(i, UpdatedBitPattern[i]));
                }
            }
        }

        [TestClass]
        public class When_updating_with_index_below_bounds : With_BitMask
        {
            [TestInitialize]
            public override void Given()
            {
                _systemUnderTest = new BitMask(DefaultBitPattern.Count);
            }

            [TestMethod]
            public void Should_throw_argument_out_of_range_exception()
            {
                AssertException.Throws<ArgumentOutOfRangeException>(() =>
                    {
                        _systemUnderTest[-1] = false;
                    });
            }
        }

        [TestClass]
        public class When_updating_with_index_above_bounds : With_BitMask
        {
            [TestInitialize]
            public override void Given()
            {
                _systemUnderTest = new BitMask(DefaultBitPattern.Count);
            }

            [TestMethod]
            public void Should_throw_argument_out_of_range_exception()
            {
                AssertException.Throws<ArgumentOutOfRangeException>(() => _systemUnderTest[DefaultBitPattern.Count] = false);
            }
        }
        
        [TestClass]
        public class When_cleared : With_BitMask
        {
            [TestInitialize]
            public override void Given()
            {
                _systemUnderTest = FromBitPattern(DefaultBitPattern);
                _systemUnderTest.Clear();
            }

            [TestMethod]
            public void Should_set_each_bit_to_false()
            {
                AssertAllFalse();
            }

            [TestMethod]
            public void Should_not_modify_count()
            {
                Assert.AreEqual(DefaultBitPattern.Count, _systemUnderTest.Count);
            }
        }

        [TestClass]
        public class When_empty_is_cleared : With_BitMask
        {
            [TestInitialize]
            public override void Given()
            {
                _systemUnderTest = new BitMask(0);
            }

            [TestMethod]
            public void Should_not_throw_exception()
            {
                _systemUnderTest.Clear();
            }
        }
    }
}
